ποΈGitΠ―ΡΠ°ποΈ
Node / meshtastic / Meshtastic-Android / files / core / database / src / commonTest / kotlin / org / meshtastic / core / database / dao / PacketDaoAtomicTransactionTest.kt
Displaying Raw β’ Download
core/database/src/commonTest/kotlin/org/meshtastic/core/database/dao/PacketDaoAtomicTransactionTest.kt d5848ad5e02bd9b5b1726bedfa51ceb0faaa0240 (d5848ad5) Text, 38.46 KB
T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.core.database.dao
Tff7b72import T7ee787androidx.room3.executeSQL
Tff7b72import T7ee787androidx.room3.useWriterConnection
Tff7b72import T7ee787kotlinx.coroutines.CompletableDeferred
Tff7b72import T7ee787kotlinx.coroutines.CoroutineStart
Tff7b72import T7ee787kotlinx.coroutines.Dispatchers
Tff7b72import T7ee787kotlinx.coroutines.async
Tff7b72import T7ee787kotlinx.coroutines.awaitAll
Tff7b72import T7ee787kotlinx.coroutines.flow.first
Tff7b72import T7ee787kotlinx.coroutines.test.runTest
Tff7b72import T7ee787okio.ByteString
Tff7b72import T7ee787okio.ByteString.Companion.toByteString
Tff7b72import T7ee787org.meshtastic.core.database.DatabaseConstants.SQLITE_MAX_BIND_PARAMETERS
Tff7b72import T7ee787org.meshtastic.core.database.MeshtasticDatabase
Tff7b72import T7ee787org.meshtastic.core.database.entity.ContactSettings
Tff7b72import T7ee787org.meshtastic.core.database.entity.MyNodeEntity
Tff7b72import T7ee787org.meshtastic.core.database.entity.Packet
Tff7b72import T7ee787org.meshtastic.core.database.entity.ReactionEntity
Tff7b72import T7ee787org.meshtastic.core.database.getInMemoryDatabaseBuilder
Tff7b72import T7ee787org.meshtastic.core.model.DataPacket
Tff7b72import T7ee787org.meshtastic.core.model.MessageStatus
Tff7b72import T7ee787org.meshtastic.core.model.NodeAddress
Tff7b72import T7ee787org.meshtastic.proto.PortNum
Tff7b72import T7ee787kotlin.test.AfterTest
Tff7b72import T7ee787kotlin.test.BeforeTest
Tff7b72import T7ee787kotlin.test.Test
Tff7b72import T7ee787kotlin.test.assertEquals
Tff7b72import T7ee787kotlin.test.assertFails
Tff7b72import T7ee787kotlin.test.assertNotNull
Tff7b72import T7ee787kotlin.test.assertNull
Tff7b72import T7ee787kotlin.test.assertTrue
T8b949e/**
* Verifies the read-modify-write helpers in [PacketDao]. Targeted failure injection proves rollback for insert/update,
* cross-table status, and multi-chunk delete transactions; a barrier-started contention case verifies monotonic
* convergence, while the remaining cases cover identity-key matching and no-downgrade rules.
*/
Tff7b72class T56d364PacketDaoAtomicTransactionTest Tb4b4b4{
Tff7b72private Tff7b72lateinit Tff7b72var Te6edf3databaseTb4b4b4: Te6edf3MeshtasticDatabase
Tff7b72private Tff7b72lateinit Tff7b72var Te6edf3packetDaoTb4b4b4: Te6edf3PacketDao
Tff7b72private Tff7b72val Te6edf3myNodeNum Tff7b72= T79c0ff4T79c0ff2T79c0ff4T79c0ff2T79c0ff4T79c0ff2T79c0ff4T79c0ff2
Tff7b72private Tff7b72val Te6edf3sfppHashTb4b4b4: Te6edf3ByteString Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4, T79c0ff2Tb4b4b4, T79c0ff3Tb4b4b4, T79c0ff4Tb4b4b4, T79c0ff5Tb4b4b4, T79c0ff6Tb4b4b4, T79c0ff7Tb4b4b4, T79c0ff8Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)
Tff7b72private Tff7b72val Te6edf3otherHashTb4b4b4: Te6edf3ByteString Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff9Tb4b4b4, T79c0ff1T79c0ff0Tb4b4b4, T79c0ff1T79c0ff1Tb4b4b4, T79c0ff1T79c0ff2Tb4b4b4, T79c0ff1T79c0ff3Tb4b4b4, T79c0ff1T79c0ff4Tb4b4b4, T79c0ff1T79c0ff5Tb4b4b4, T79c0ff1T79c0ff6Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)
Tff7b72private Tff7b72val Te6edf3myNodeEntity Tff7b72=
Te6edf3MyNodeEntityTb4b4b4(
Te6edf3myNodeNum Tff7b72= Te6edf3myNodeNumTb4b4b4,
Te6edf3model Tff7b72= Tff7b72nullTb4b4b4,
Te6edf3firmwareVersion Tff7b72= Tff7b72nullTb4b4b4,
Te6edf3couldUpdate Tff7b72= Tff7b72falseTb4b4b4,
Te6edf3shouldUpdate Tff7b72= Tff7b72falseTb4b4b4,
Te6edf3currentPacketId Tff7b72= T79c0ff1LTb4b4b4,
Te6edf3messageTimeoutMsec Tff7b72= T79c0ff5 Tff7b72* T79c0ff6T79c0ff0 Tff7b72* T79c0ff1T79c0ff0T79c0ff0T79c0ff0Tb4b4b4,
Te6edf3minAppVersion Tff7b72= T79c0ff1Tb4b4b4,
Te6edf3maxChannels Tff7b72= T79c0ff8Tb4b4b4,
Te6edf3hasWifi Tff7b72= Tff7b72falseTb4b4b4,
Tb4b4b4)
Tf0883e@BeforeTest
Tff7b72fun Td2a8ffsetUpTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3database Tff7b72= Te6edf3getInMemoryDatabaseBuilderTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3buildTb4b4b4(Tb4b4b4)
Te6edf3packetDao Tff7b72= Te6edf3databaseTb4b4b4.Te6edf3packetDaoTb4b4b4(Tb4b4b4)
Tb4b4b4}
T8b949e/** Seeds the MyNodeInfo row required by packet queries. Must be called inside each test's runTest block. */
Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffseedMyNodeInfoTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3databaseTb4b4b4.Te6edf3nodeInfoDaoTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3setMyNodeInfoTb4b4b4(Te6edf3myNodeEntityTb4b4b4)
Tb4b4b4}
Tf0883e@AfterTest
Tff7b72fun Td2a8fftearDownTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3databaseTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)
Tb4b4b4}
T8b949e// ββ Helpers ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Tff7b72private Tff7b72fun Td2a8fftextPacketTb4b4b4(
Te6edf3contactTb4b4b4: Tffa657StringTb4b4b4,
Te6edf3textTb4b4b4: Tffa657StringTb4b4b4,
Te6edf3timeTb4b4b4: Tffa657LongTb4b4b4,
Te6edf3packetIdTb4b4b4: Tffa657Int Tff7b72= T79c0ff0Tb4b4b4,
Te6edf3fromTb4b4b4: Tffa657String? Tff7b72= Te6edf3NodeAddressTb4b4b4.Te6edf3ID_LOCALTb4b4b4,
Te6edf3toTb4b4b4: Tffa657String? Tff7b72= Te6edf3NodeAddressTb4b4b4.Te6edf3ID_BROADCASTTb4b4b4,
Te6edf3statusTb4b4b4: Te6edf3MessageStatus Tff7b72= Te6edf3MessageStatusTb4b4b4.Te6edf3UNKNOWNTb4b4b4,
Te6edf3routingErrorTb4b4b4: Tffa657Int Tff7b72= Tff7b72-T79c0ff1Tb4b4b4,
Te6edf3sfppHashTb4b4b4: Te6edf3ByteString? Tff7b72= Tff7b72nullTb4b4b4,
Te6edf3ownerNodeNumTb4b4b4: Tffa657Int Tff7b72= Te6edf3myNodeNumTb4b4b4,
Tb4b4b4) Tff7b72= Te6edf3PacketTb4b4b4(
Te6edf3uuid Tff7b72= T79c0ff0LTb4b4b4,
Te6edf3myNodeNum Tff7b72= Te6edf3ownerNodeNumTb4b4b4,
Te6edf3port_num Tff7b72= Te6edf3PortNumTb4b4b4.Te6edf3TEXT_MESSAGE_APPTb4b4b4.Te6edf3valueTb4b4b4,
Te6edf3contact_key Tff7b72= Te6edf3contactTb4b4b4,
Te6edf3received_time Tff7b72= Te6edf3timeTb4b4b4,
Te6edf3read Tff7b72= Tff7b72trueTb4b4b4,
Te6edf3data Tff7b72=
Te6edf3DataPacketTb4b4b4(
Te6edf3to Tff7b72= Te6edf3toTb4b4b4,
Te6edf3bytes Tff7b72= Te6edf3textTb4b4b4.Te6edf3encodeToByteArrayTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3dataType Tff7b72= Te6edf3PortNumTb4b4b4.Te6edf3TEXT_MESSAGE_APPTb4b4b4.Te6edf3valueTb4b4b4,
Te6edf3from Tff7b72= Te6edf3fromTb4b4b4,
Te6edf3id Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3status Tff7b72= Te6edf3statusTb4b4b4,
Te6edf3sfppHash Tff7b72= Te6edf3sfppHashTb4b4b4,
Tb4b4b4)Tb4b4b4,
Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3routingError Tff7b72= Te6edf3routingErrorTb4b4b4,
Te6edf3sfpp_hash Tff7b72= Te6edf3sfppHashTb4b4b4,
Te6edf3messageText Tff7b72= Te6edf3textTb4b4b4,
Tb4b4b4)
Tff7b72private Tff7b72fun Td2a8ffreactionTb4b4b4(
Te6edf3replyIdTb4b4b4: Tffa657IntTb4b4b4,
Te6edf3userIdTb4b4b4: Tffa657StringTb4b4b4,
Te6edf3emojiTb4b4b4: Tffa657StringTb4b4b4,
Te6edf3timestampTb4b4b4: Tffa657LongTb4b4b4,
Te6edf3packetIdTb4b4b4: Tffa657Int Tff7b72= Te6edf3replyIdTb4b4b4,
Te6edf3toTb4b4b4: Tffa657String? Tff7b72= Tff7b72nullTb4b4b4,
Te6edf3statusTb4b4b4: Te6edf3MessageStatus Tff7b72= Te6edf3MessageStatusTb4b4b4.Te6edf3UNKNOWNTb4b4b4,
Te6edf3sfppHashTb4b4b4: Te6edf3ByteString? Tff7b72= Tff7b72nullTb4b4b4,
Te6edf3ownerNodeNumTb4b4b4: Tffa657Int Tff7b72= Te6edf3myNodeNumTb4b4b4,
Tb4b4b4) Tff7b72= Te6edf3ReactionEntityTb4b4b4(
Te6edf3myNodeNum Tff7b72= Te6edf3ownerNodeNumTb4b4b4,
Te6edf3replyId Tff7b72= Te6edf3replyIdTb4b4b4,
Te6edf3userId Tff7b72= Te6edf3userIdTb4b4b4,
Te6edf3emoji Tff7b72= Te6edf3emojiTb4b4b4,
Te6edf3timestamp Tff7b72= Te6edf3timestampTb4b4b4,
Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3to Tff7b72= Te6edf3toTb4b4b4,
Te6edf3status Tff7b72= Te6edf3statusTb4b4b4,
Te6edf3sfpp_hash Tff7b72= Te6edf3sfppHashTb4b4b4,
Tb4b4b4)
T8b949e/** Places [first] in a full bind-param chunk and [second] in the next chunk without inserting filler rows. */
Tff7b72private Tff7b72fun Td2a8ffcrossChunkUuidsTb4b4b4(Te6edf3firstTb4b4b4: Tffa657LongTb4b4b4, Te6edf3secondTb4b4b4: Tffa657LongTb4b4b4)Tb4b4b4: Te6edf3ListTff7b72<Tffa657LongTff7b72> Tff7b72= Te6edf3buildList Tb4b4b4{
Te6edf3addTb4b4b4(Te6edf3firstTb4b4b4)
Te6edf3repeatTb4b4b4(Te6edf3SQLITE_MAX_BIND_PARAMETERS Tff7b72- T79c0ff1Tb4b4b4) Tb4b4b4{ Te6edf3addTb4b4b4(Tff7b72-Tb4b4b4(Tffa657it Tff7b72+ T79c0ff1LTb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3addTb4b4b4(Te6edf3secondTb4b4b4)
Tb4b4b4}
T8b949e// ββ updateLastReadMessage ββββββββββββββββββββββββββββββββββββββββββββββββββββ
Tf0883e@Test
Tff7b72fun Td2a8ffrssiRoundTripsAbsentAndZeroDistinctlyTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3contact Tff7b72= Ta5d6ff"Ta5d6ff0Tffd700${Te6edf3NodeAddressTb4b4b4.Te6edf3ID_BROADCASTTffd700}Ta5d6ff"
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3textPacketTb4b4b4(Te6edf3contactTb4b4b4, Ta5d6ff"Ta5d6ffno readingTa5d6ff"Tb4b4b4, Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff0T79c0ff0LTb4b4b4)Tb4b4b4.Te6edf3copyTb4b4b4(Te6edf3rssi Tff7b72= Tff7b72nullTb4b4b4)Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3textPacketTb4b4b4(Te6edf3contactTb4b4b4, Ta5d6ff"Ta5d6ffzero dBmTa5d6ff"Tb4b4b4, Te6edf3time Tff7b72= T79c0ff2T79c0ff0T79c0ff0T79c0ff0LTb4b4b4)Tb4b4b4.Te6edf3copyTb4b4b4(Te6edf3rssi Tff7b72= T79c0ff0Tb4b4b4)Tb4b4b4)
T8b949e// Order-independent: the query returns newest-first, which is not what this test is about.
Tff7b72val Te6edf3stored Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3getMessagesFromTb4b4b4(Te6edf3contactTb4b4b4)Tb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3map Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3packetTb4b4b4.Te6edf3rssi Tb4b4b4}Tb4b4b4.Te6edf3toSetTb4b4b4(Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3setOfTb4b4b4(Tff7b72nullTb4b4b4, T79c0ff0Tb4b4b4)Tb4b4b4, Te6edf3storedTb4b4b4, Ta5d6ff"Ta5d6ff0 dBm is a real reading and must not collapse into absentTa5d6ff"Tb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffupdateLastReadMessageCreatesSettingsWhenAbsentTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3contact Tff7b72= Ta5d6ff"Ta5d6ff0Tffd700${Te6edf3NodeAddressTb4b4b4.Te6edf3ID_BROADCASTTffd700}Ta5d6ff"
Te6edf3packetDaoTb4b4b4.Te6edf3updateLastReadMessageTb4b4b4(Te6edf3contactTb4b4b4, Te6edf3messageUuid Tff7b72= T79c0ff4T79c0ff2LTb4b4b4, Te6edf3lastReadTimestamp Tff7b72= T79c0ff1T79c0ff0T79c0ff0T79c0ff0LTb4b4b4)
Tff7b72val Te6edf3settings Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3getContactSettingsTb4b4b4(Te6edf3contactTb4b4b4)
Te6edf3assertNotNullTb4b4b4(Te6edf3settingsTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff4T79c0ff2LTb4b4b4, Te6edf3settingsTb4b4b4.Te6edf3lastReadMessageUuidTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff1T79c0ff0T79c0ff0T79c0ff0LTb4b4b4, Te6edf3settingsTb4b4b4.Te6edf3lastReadMessageTimestampTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffupdateLastReadMessageRollsBackInsertedSettingsWhenUpdateFailsTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3contact Tff7b72= Ta5d6ff"Ta5d6ffrollback-contactTa5d6ff"
Te6edf3databaseTb4b4b4.Te6edf3useWriterConnection Tb4b4b4{
Tffa657itTb4b4b4.Te6edf3executeSQLTb4b4b4(
Ta5d6ff"""
Ta5d6ff CREATE TRIGGER fail_last_read_update
BEFORE UPDATE ON contact_settings
WHEN OLD.contact_key = 'Tffd700$Te6edf3contactTa5d6ff'
BEGIN
SELECT RAISE(ABORT, 'forced last-read update failure');
END
Ta5d6ff"""
Tb4b4b4.Te6edf3trimIndentTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Te6edf3assertFails Tb4b4b4{ Te6edf3packetDaoTb4b4b4.Te6edf3updateLastReadMessageTb4b4b4(Te6edf3contactTb4b4b4, Te6edf3messageUuid Tff7b72= T79c0ff4T79c0ff2LTb4b4b4, Te6edf3lastReadTimestamp Tff7b72= T79c0ff1T79c0ff0T79c0ff0T79c0ff0LTb4b4b4) Tb4b4b4}
Te6edf3assertNullTb4b4b4(Te6edf3packetDaoTb4b4b4.Te6edf3getContactSettingsTb4b4b4(Te6edf3contactTb4b4b4)Tb4b4b4, Ta5d6ff"Ta5d6ffthe preceding insert must roll back with the failed updateTa5d6ff"Tb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffupdateLastReadMessageAcceptsNewerTimestampTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3contact Tff7b72= Ta5d6ff"Ta5d6ff0Tffd700${Te6edf3NodeAddressTb4b4b4.Te6edf3ID_BROADCASTTffd700}Ta5d6ff"
Te6edf3packetDaoTb4b4b4.Te6edf3updateLastReadMessageTb4b4b4(Te6edf3contactTb4b4b4, Te6edf3messageUuid Tff7b72= T79c0ff4T79c0ff2LTb4b4b4, Te6edf3lastReadTimestamp Tff7b72= T79c0ff2T79c0ff0T79c0ff0T79c0ff0LTb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3updateLastReadMessageTb4b4b4(Te6edf3contactTb4b4b4, Te6edf3messageUuid Tff7b72= T79c0ff9T79c0ff9LTb4b4b4, Te6edf3lastReadTimestamp Tff7b72= T79c0ff3T79c0ff0T79c0ff0T79c0ff0LTb4b4b4)
Tff7b72val Te6edf3settings Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3getContactSettingsTb4b4b4(Te6edf3contactTb4b4b4)
Te6edf3assertNotNullTb4b4b4(Te6edf3settingsTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff9T79c0ff9LTb4b4b4, Te6edf3settingsTb4b4b4.Te6edf3lastReadMessageUuidTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff3T79c0ff0T79c0ff0T79c0ff0LTb4b4b4, Te6edf3settingsTb4b4b4.Te6edf3lastReadMessageTimestampTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffupdateLastReadMessageRejectsOlderTimestampTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3contact Tff7b72= Ta5d6ff"Ta5d6ff0Tffd700${Te6edf3NodeAddressTb4b4b4.Te6edf3ID_BROADCASTTffd700}Ta5d6ff"
Te6edf3packetDaoTb4b4b4.Te6edf3updateLastReadMessageTb4b4b4(Te6edf3contactTb4b4b4, Te6edf3messageUuid Tff7b72= T79c0ff4T79c0ff2LTb4b4b4, Te6edf3lastReadTimestamp Tff7b72= T79c0ff2T79c0ff0T79c0ff0T79c0ff0LTb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3updateLastReadMessageTb4b4b4(Te6edf3contactTb4b4b4, Te6edf3messageUuid Tff7b72= T79c0ff9T79c0ff9LTb4b4b4, Te6edf3lastReadTimestamp Tff7b72= T79c0ff1T79c0ff0T79c0ff0T79c0ff0LTb4b4b4)
Tff7b72val Te6edf3settings Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3getContactSettingsTb4b4b4(Te6edf3contactTb4b4b4)
Te6edf3assertNotNullTb4b4b4(Te6edf3settingsTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff4T79c0ff2LTb4b4b4, Te6edf3settingsTb4b4b4.Te6edf3lastReadMessageUuidTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff2T79c0ff0T79c0ff0T79c0ff0LTb4b4b4, Te6edf3settingsTb4b4b4.Te6edf3lastReadMessageTimestampTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffconcurrentLastReadUpdatesConvergeOnNewestTimestampTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3contact Tff7b72= Ta5d6ff"Ta5d6ffconcurrent-last-readTa5d6ff"
Tff7b72val Te6edf3start Tff7b72= Te6edf3CompletableDeferredTff7b72<Tffa657UnitTff7b72>Tb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3updates Tff7b72=
Te6edf3listOfTb4b4b4(
Te6edf3asyncTb4b4b4(Te6edf3DispatchersTb4b4b4.Te6edf3DefaultTb4b4b4, Te6edf3start Tff7b72= Te6edf3CoroutineStartTb4b4b4.Te6edf3UNDISPATCHEDTb4b4b4) Tb4b4b4{
Te6edf3startTb4b4b4.Te6edf3awaitTb4b4b4(Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3updateLastReadMessageTb4b4b4(Te6edf3contactTb4b4b4, Te6edf3messageUuid Tff7b72= T79c0ff4T79c0ff2LTb4b4b4, Te6edf3lastReadTimestamp Tff7b72= T79c0ff2T79c0ff0T79c0ff0T79c0ff0LTb4b4b4)
Tb4b4b4}Tb4b4b4,
Te6edf3asyncTb4b4b4(Te6edf3DispatchersTb4b4b4.Te6edf3DefaultTb4b4b4, Te6edf3start Tff7b72= Te6edf3CoroutineStartTb4b4b4.Te6edf3UNDISPATCHEDTb4b4b4) Tb4b4b4{
Te6edf3startTb4b4b4.Te6edf3awaitTb4b4b4(Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3updateLastReadMessageTb4b4b4(Te6edf3contactTb4b4b4, Te6edf3messageUuid Tff7b72= T79c0ff9T79c0ff9LTb4b4b4, Te6edf3lastReadTimestamp Tff7b72= T79c0ff3T79c0ff0T79c0ff0T79c0ff0LTb4b4b4)
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Te6edf3startTb4b4b4.Te6edf3completeTb4b4b4(Tffa657UnitTb4b4b4)
Te6edf3updatesTb4b4b4.Te6edf3awaitAllTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3settings Tff7b72= Te6edf3assertNotNullTb4b4b4(Te6edf3packetDaoTb4b4b4.Te6edf3getContactSettingsTb4b4b4(Te6edf3contactTb4b4b4)Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff9T79c0ff9LTb4b4b4, Te6edf3settingsTb4b4b4.Te6edf3lastReadMessageUuidTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff3T79c0ff0T79c0ff0T79c0ff0LTb4b4b4, Te6edf3settingsTb4b4b4.Te6edf3lastReadMessageTimestampTb4b4b4)
Tb4b4b4}
T8b949e/**
* Verifies that [PacketDao.updateLastReadMessage] preserves unrelated contact-settings columns (muteUntil,
* filteringDisabled) that were set before the last-read update. The INSERT-IGNORE + conditional-UPDATE pattern must
* never overwrite these fields with defaults.
*/
Tf0883e@Test
Tff7b72fun Td2a8ffupdateLastReadMessagePreservesUnrelatedFieldsTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3contact Tff7b72= Ta5d6ff"Ta5d6ff0Tffd700${Te6edf3NodeAddressTb4b4b4.Te6edf3ID_BROADCASTTffd700}Ta5d6ff"
T8b949e// Seed with non-default muteUntil and filteringDisabled
Te6edf3packetDaoTb4b4b4.Te6edf3insertContactSettingsIgnoreTb4b4b4(
Te6edf3listOfTb4b4b4(Te6edf3ContactSettingsTb4b4b4(Te6edf3contact_key Tff7b72= Te6edf3contactTb4b4b4, Te6edf3muteUntil Tff7b72= T79c0ff9T79c0ff9T79c0ff9Te6edf3_999_999LTb4b4b4, Te6edf3filteringDisabled Tff7b72= Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Tb4b4b4)
T8b949e// Perform the last-read update (newer timestamp)
Te6edf3packetDaoTb4b4b4.Te6edf3updateLastReadMessageTb4b4b4(Te6edf3contactTb4b4b4, Te6edf3messageUuid Tff7b72= T79c0ff4T79c0ff2LTb4b4b4, Te6edf3lastReadTimestamp Tff7b72= T79c0ff3T79c0ff0T79c0ff0T79c0ff0LTb4b4b4)
Tff7b72val Te6edf3settings Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3getContactSettingsTb4b4b4(Te6edf3contactTb4b4b4)
Te6edf3assertNotNullTb4b4b4(Te6edf3settingsTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff4T79c0ff2LTb4b4b4, Te6edf3settingsTb4b4b4.Te6edf3lastReadMessageUuidTb4b4b4, Ta5d6ff"Ta5d6fflastReadMessageUuid should be updatedTa5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff3T79c0ff0T79c0ff0T79c0ff0LTb4b4b4, Te6edf3settingsTb4b4b4.Te6edf3lastReadMessageTimestampTb4b4b4, Ta5d6ff"Ta5d6fflastReadMessageTimestamp should be updatedTa5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff9T79c0ff9T79c0ff9Te6edf3_999_999LTb4b4b4, Te6edf3settingsTb4b4b4.Te6edf3muteUntilTb4b4b4, Ta5d6ff"Ta5d6ffmuteUntil must be preservedTa5d6ff"Tb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3settingsTb4b4b4.Te6edf3filteringDisabledTb4b4b4, Ta5d6ff"Ta5d6fffilteringDisabled must be preservedTa5d6ff"Tb4b4b4)
Tb4b4b4}
T8b949e/** Verifies that updating contact A's last-read position does not alter contact B. */
Tf0883e@Test
Tff7b72fun Td2a8ffupdateLastReadMessageIsContactScopedTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3contactA Tff7b72= Ta5d6ff"Ta5d6ff0Tffd700${Te6edf3NodeAddressTb4b4b4.Te6edf3ID_BROADCASTTffd700}Ta5d6ff"
Tff7b72val Te6edf3contactB Tff7b72= Ta5d6ff"Ta5d6ff0!abcdef01Ta5d6ff"
Te6edf3packetDaoTb4b4b4.Te6edf3updateLastReadMessageTb4b4b4(Te6edf3contactATb4b4b4, Te6edf3messageUuid Tff7b72= T79c0ff1T79c0ff0LTb4b4b4, Te6edf3lastReadTimestamp Tff7b72= T79c0ff1T79c0ff0T79c0ff0T79c0ff0LTb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3updateLastReadMessageTb4b4b4(Te6edf3contactBTb4b4b4, Te6edf3messageUuid Tff7b72= T79c0ff2T79c0ff0LTb4b4b4, Te6edf3lastReadTimestamp Tff7b72= T79c0ff2T79c0ff0T79c0ff0T79c0ff0LTb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3updateLastReadMessageTb4b4b4(Te6edf3contactATb4b4b4, Te6edf3messageUuid Tff7b72= T79c0ff3T79c0ff0LTb4b4b4, Te6edf3lastReadTimestamp Tff7b72= T79c0ff3T79c0ff0T79c0ff0T79c0ff0LTb4b4b4)
Tff7b72val Te6edf3settingsA Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3getContactSettingsTb4b4b4(Te6edf3contactATb4b4b4)
Te6edf3assertNotNullTb4b4b4(Te6edf3settingsATb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff3T79c0ff0LTb4b4b4, Te6edf3settingsATb4b4b4.Te6edf3lastReadMessageUuidTb4b4b4, Ta5d6ff"Ta5d6ffcontact A updated to 30Ta5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff3T79c0ff0T79c0ff0T79c0ff0LTb4b4b4, Te6edf3settingsATb4b4b4.Te6edf3lastReadMessageTimestampTb4b4b4)
Tff7b72val Te6edf3settingsB Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3getContactSettingsTb4b4b4(Te6edf3contactBTb4b4b4)
Te6edf3assertNotNullTb4b4b4(Te6edf3settingsBTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff2T79c0ff0LTb4b4b4, Te6edf3settingsBTb4b4b4.Te6edf3lastReadMessageUuidTb4b4b4, Ta5d6ff"Ta5d6ffcontact B unchanged at 20Ta5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff2T79c0ff0T79c0ff0T79c0ff0LTb4b4b4, Te6edf3settingsBTb4b4b4.Te6edf3lastReadMessageTimestampTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffupdateLastReadMessageEqualTimestampIsNoOpTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3contact Tff7b72= Ta5d6ff"Ta5d6ff0Tffd700${Te6edf3NodeAddressTb4b4b4.Te6edf3ID_BROADCASTTffd700}Ta5d6ff"
Te6edf3packetDaoTb4b4b4.Te6edf3updateLastReadMessageTb4b4b4(Te6edf3contactTb4b4b4, Te6edf3messageUuid Tff7b72= T79c0ff4T79c0ff2LTb4b4b4, Te6edf3lastReadTimestamp Tff7b72= T79c0ff2T79c0ff0T79c0ff0T79c0ff0LTb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3updateLastReadMessageTb4b4b4(Te6edf3contactTb4b4b4, Te6edf3messageUuid Tff7b72= T79c0ff9T79c0ff9LTb4b4b4, Te6edf3lastReadTimestamp Tff7b72= T79c0ff2T79c0ff0T79c0ff0T79c0ff0LTb4b4b4)
Tff7b72val Te6edf3settings Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3getContactSettingsTb4b4b4(Te6edf3contactTb4b4b4)
Te6edf3assertNotNullTb4b4b4(Te6edf3settingsTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff4T79c0ff2LTb4b4b4, Te6edf3settingsTb4b4b4.Te6edf3lastReadMessageUuidTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff2T79c0ff0T79c0ff0T79c0ff0LTb4b4b4, Te6edf3settingsTb4b4b4.Te6edf3lastReadMessageTimestampTb4b4b4)
Tb4b4b4}
T8b949e// ββ updatePacketByKey ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Tf0883e@Test
Tff7b72fun Td2a8ffupdatePacketByKeyUpdatesOnlyMatchingIdentityTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3matching Tff7b72= Te6edf3textPacketTb4b4b4(Ta5d6ff"Ta5d6ffcontactTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmatchTa5d6ff"Tb4b4b4, Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4, Te6edf3packetId Tff7b72= T79c0ff5T79c0ff0Tb4b4b4, Te6edf3from Tff7b72= Ta5d6ff"Ta5d6ff!aaTa5d6ff"Tb4b4b4, Te6edf3to Tff7b72= Ta5d6ff"Ta5d6ff^allTa5d6ff"Tb4b4b4)
Tff7b72val Te6edf3sameIdDiffFrom Tff7b72= Te6edf3textPacketTb4b4b4(Ta5d6ff"Ta5d6ffcontactTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffotherTa5d6ff"Tb4b4b4, Te6edf3time Tff7b72= T79c0ff2T79c0ff0T79c0ff0Tb4b4b4, Te6edf3packetId Tff7b72= T79c0ff5T79c0ff0Tb4b4b4, Te6edf3from Tff7b72= Ta5d6ff"Ta5d6ff!bbTa5d6ff"Tb4b4b4, Te6edf3to Tff7b72= Ta5d6ff"Ta5d6ff^allTa5d6ff"Tb4b4b4)
Tff7b72val Te6edf3sameIdFromDiffTo Tff7b72= Te6edf3textPacketTb4b4b4(Ta5d6ff"Ta5d6ffcontactTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffother-toTa5d6ff"Tb4b4b4, Te6edf3time Tff7b72= T79c0ff3T79c0ff0T79c0ff0Tb4b4b4, Te6edf3packetId Tff7b72= T79c0ff5T79c0ff0Tb4b4b4, Te6edf3from Tff7b72= Ta5d6ff"Ta5d6ff!aaTa5d6ff"Tb4b4b4, Te6edf3to Tff7b72= Ta5d6ff"Ta5d6ff!ccTa5d6ff"Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3matchingTb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3sameIdDiffFromTb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3sameIdFromDiffToTb4b4b4)
Tff7b72val Te6edf3newData Tff7b72= Te6edf3matchingTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3status Tff7b72= Te6edf3MessageStatusTb4b4b4.Te6edf3DELIVEREDTb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3updatePacketByKeyTb4b4b4(Te6edf3newDataTb4b4b4, Te6edf3routingError Tff7b72= Tff7b72-T79c0ff1Tb4b4b4)
Tff7b72val Te6edf3packets Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findPacketsWithIdTb4b4b4(T79c0ff5T79c0ff0Tb4b4b4)
Tff7b72val Te6edf3updated Tff7b72= Te6edf3packetsTb4b4b4.Te6edf3find Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3from Tff7b72=Tff7b72= Ta5d6ff"Ta5d6ff!aaTa5d6ff" Tff7b72&Tff7b72& Tffa657itTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3to Tff7b72=Tff7b72= Ta5d6ff"Ta5d6ff^allTa5d6ff" Tb4b4b4}
Tff7b72val Te6edf3untouchedFrom Tff7b72= Te6edf3packetsTb4b4b4.Te6edf3find Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3from Tff7b72=Tff7b72= Ta5d6ff"Ta5d6ff!bbTa5d6ff" Tb4b4b4}
Tff7b72val Te6edf3untouchedTo Tff7b72= Te6edf3packetsTb4b4b4.Te6edf3find Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3from Tff7b72=Tff7b72= Ta5d6ff"Ta5d6ff!aaTa5d6ff" Tff7b72&Tff7b72& Tffa657itTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3to Tff7b72=Tff7b72= Ta5d6ff"Ta5d6ff!ccTa5d6ff" Tb4b4b4}
Te6edf3assertEqualsTb4b4b4(Te6edf3MessageStatusTb4b4b4.Te6edf3DELIVEREDTb4b4b4, Te6edf3updatedTff7b72?.Te6edf3dataTff7b72?.Te6edf3statusTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3MessageStatusTb4b4b4.Te6edf3UNKNOWNTb4b4b4, Te6edf3untouchedFromTff7b72?.Te6edf3dataTff7b72?.Te6edf3statusTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3MessageStatusTb4b4b4.Te6edf3UNKNOWNTb4b4b4, Te6edf3untouchedToTff7b72?.Te6edf3dataTff7b72?.Te6edf3statusTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffupdatePacketByKeyUpdatesEveryOwnershipScopedCopyTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3canonical Tff7b72= Te6edf3textPacketTb4b4b4(Ta5d6ff"Ta5d6ffcontactTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffcanonicalTa5d6ff"Tb4b4b4, Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4, Te6edf3packetId Tff7b72= T79c0ff5T79c0ff5Tb4b4b4, Te6edf3from Tff7b72= Ta5d6ff"Ta5d6ff!aaTa5d6ff"Tb4b4b4, Te6edf3to Tff7b72= Ta5d6ff"Ta5d6ff^allTa5d6ff"Tb4b4b4)
Tff7b72val Te6edf3legacy Tff7b72=
Te6edf3textPacketTb4b4b4(Ta5d6ff"Ta5d6ffcontactTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6fflegacyTa5d6ff"Tb4b4b4, Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff1Tb4b4b4, Te6edf3packetId Tff7b72= T79c0ff5T79c0ff5Tb4b4b4, Te6edf3from Tff7b72= Ta5d6ff"Ta5d6ff!aaTa5d6ff"Tb4b4b4, Te6edf3to Tff7b72= Ta5d6ff"Ta5d6ff^allTa5d6ff"Tb4b4b4, Te6edf3ownerNodeNum Tff7b72= T79c0ff0Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3canonicalTb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3legacyTb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3updatePacketByKeyTb4b4b4(Te6edf3canonicalTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3status Tff7b72= Te6edf3MessageStatusTb4b4b4.Te6edf3DELIVEREDTb4b4b4)Tb4b4b4, Te6edf3routingError Tff7b72= T79c0ff4Tb4b4b4)
Tff7b72val Te6edf3matching Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findPacketsWithIdTb4b4b4(T79c0ff5T79c0ff5Tb4b4b4)Tb4b4b4.Te6edf3filter Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3from Tff7b72=Tff7b72= Ta5d6ff"Ta5d6ff!aaTa5d6ff" Tff7b72&Tff7b72& Tffa657itTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3to Tff7b72=Tff7b72= Ta5d6ff"Ta5d6ff^allTa5d6ff" Tb4b4b4}
Te6edf3assertEqualsTb4b4b4(T79c0ff2Tb4b4b4, Te6edf3matchingTb4b4b4.Te6edf3sizeTb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3matchingTb4b4b4.Te6edf3all Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3status Tff7b72=Tff7b72= Te6edf3MessageStatusTb4b4b4.Te6edf3DELIVERED Tb4b4b4}Tb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3matchingTb4b4b4.Te6edf3all Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3routingError Tff7b72=Tff7b72= T79c0ff4 Tb4b4b4}Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3setOfTb4b4b4(T79c0ff0Tb4b4b4, Te6edf3myNodeNumTb4b4b4)Tb4b4b4, Te6edf3matchingTb4b4b4.Te6edf3map Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3myNodeNum Tb4b4b4}Tb4b4b4.Te6edf3toSetTb4b4b4(Tb4b4b4)Tb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffupdatePacketByKeyAppliesRoutingErrorWhenNonNegativeTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3packet Tff7b72= Te6edf3textPacketTb4b4b4(Ta5d6ff"Ta5d6ffcontactTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmsgTa5d6ff"Tb4b4b4, Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4, Te6edf3packetId Tff7b72= T79c0ff6T79c0ff0Tb4b4b4, Te6edf3from Tff7b72= Ta5d6ff"Ta5d6ff!aaTa5d6ff"Tb4b4b4, Te6edf3to Tff7b72= Ta5d6ff"Ta5d6ff^allTa5d6ff"Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3packetTb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3updatePacketByKeyTb4b4b4(Te6edf3packetTb4b4b4.Te6edf3dataTb4b4b4, Te6edf3routingError Tff7b72= T79c0ff7Tb4b4b4)
Tff7b72val Te6edf3updated Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findPacketsWithIdTb4b4b4(T79c0ff6T79c0ff0Tb4b4b4)Tb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff7Tb4b4b4, Te6edf3updatedTb4b4b4.Te6edf3routingErrorTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffupdatePacketByKeyLeavesRoutingErrorUnchangedWhenMinusOneTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3packet Tff7b72=
Te6edf3textPacketTb4b4b4(Ta5d6ff"Ta5d6ffcontactTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmsgTa5d6ff"Tb4b4b4, Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4, Te6edf3packetId Tff7b72= T79c0ff7T79c0ff0Tb4b4b4, Te6edf3from Tff7b72= Ta5d6ff"Ta5d6ff!aaTa5d6ff"Tb4b4b4, Te6edf3to Tff7b72= Ta5d6ff"Ta5d6ff^allTa5d6ff"Tb4b4b4, Te6edf3routingError Tff7b72= T79c0ff3Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3packetTb4b4b4)
Tff7b72val Te6edf3newData Tff7b72= Te6edf3packetTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3status Tff7b72= Te6edf3MessageStatusTb4b4b4.Te6edf3DELIVEREDTb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3updatePacketByKeyTb4b4b4(Te6edf3newDataTb4b4b4, Te6edf3routingError Tff7b72= Tff7b72-T79c0ff1Tb4b4b4)
Tff7b72val Te6edf3updated Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findPacketsWithIdTb4b4b4(T79c0ff7T79c0ff0Tb4b4b4)Tb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff3Tb4b4b4, Te6edf3updatedTb4b4b4.Te6edf3routingErrorTb4b4b4, Ta5d6ff"Ta5d6ffroutingError should be preserved, not reset to -1Ta5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3MessageStatusTb4b4b4.Te6edf3DELIVEREDTb4b4b4, Te6edf3updatedTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3statusTb4b4b4)
Tb4b4b4}
T8b949e// ββ updateReactionByKey ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Tf0883e@Test
Tff7b72fun Td2a8ffupdateReactionByKeyUpdatesMatchingReactionTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3textPacketTb4b4b4(Ta5d6ff"Ta5d6ffcontactTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmsgTa5d6ff"Tb4b4b4, Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4, Te6edf3packetId Tff7b72= T79c0ff8T79c0ff0Tb4b4b4)Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3reactionTb4b4b4(Te6edf3replyId Tff7b72= T79c0ff8T79c0ff0Tb4b4b4, Te6edf3userId Tff7b72= Ta5d6ff"Ta5d6ff!uTa5d6ff"Tb4b4b4, Te6edf3emoji Tff7b72= Ta5d6ff"Ta5d6ffπTa5d6ff"Tb4b4b4, Te6edf3timestamp Tff7b72= T79c0ff1Tb4b4b4, Te6edf3packetId Tff7b72= T79c0ff8T79c0ff0Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3replacement Tff7b72=
Te6edf3reactionTb4b4b4(
Te6edf3replyId Tff7b72= T79c0ff8T79c0ff0Tb4b4b4,
Te6edf3userId Tff7b72= Ta5d6ff"Ta5d6ff!uTa5d6ff"Tb4b4b4,
Te6edf3emoji Tff7b72= Ta5d6ff"Ta5d6ffπTa5d6ff"Tb4b4b4,
Te6edf3timestamp Tff7b72= T79c0ff9T79c0ff9T79c0ff9Tb4b4b4,
Te6edf3packetId Tff7b72= T79c0ff8T79c0ff0Tb4b4b4,
Te6edf3status Tff7b72= Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_CONFIRMEDTb4b4b4,
Te6edf3sfppHash Tff7b72= Te6edf3sfppHashTb4b4b4,
Tb4b4b4)
Tb4b4b4.Te6edf3copyTb4b4b4(Te6edf3myNodeNum Tff7b72= T79c0ff0Tb4b4b4) T8b949e// placeholder β DAO must borrow from existing
Te6edf3packetDaoTb4b4b4.Te6edf3updateReactionByKeyTb4b4b4(Te6edf3replacementTb4b4b4)
Tff7b72val Te6edf3updated Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findReactionsWithIdTb4b4b4(T79c0ff8T79c0ff0Tb4b4b4)Tb4b4b4.Te6edf3find Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3userId Tff7b72=Tff7b72= Ta5d6ff"Ta5d6ff!uTa5d6ff" Tff7b72&Tff7b72& Tffa657itTb4b4b4.Te6edf3emoji Tff7b72=Tff7b72= Ta5d6ff"Ta5d6ffπTa5d6ff" Tb4b4b4}
Te6edf3assertNotNullTb4b4b4(Te6edf3updatedTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff9T79c0ff9T79c0ff9Tb4b4b4, Te6edf3updatedTb4b4b4.Te6edf3timestampTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_CONFIRMEDTb4b4b4, Te6edf3updatedTb4b4b4.Te6edf3statusTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3sfppHashTb4b4b4, Te6edf3updatedTb4b4b4.Te6edf3sfpp_hashTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffupdateReactionByKeyUpdatesEveryOwnershipScopedCopyTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3textPacketTb4b4b4(Ta5d6ff"Ta5d6ffcontactTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmsgTa5d6ff"Tb4b4b4, Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4, Te6edf3packetId Tff7b72= T79c0ff8T79c0ff4Tb4b4b4)Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3reactionTb4b4b4(Te6edf3replyId Tff7b72= T79c0ff8T79c0ff4Tb4b4b4, Te6edf3userId Tff7b72= Ta5d6ff"Ta5d6ff!uTa5d6ff"Tb4b4b4, Te6edf3emoji Tff7b72= Ta5d6ff"Ta5d6ffπTa5d6ff"Tb4b4b4, Te6edf3timestamp Tff7b72= T79c0ff1Tb4b4b4, Te6edf3packetId Tff7b72= T79c0ff8T79c0ff4Tb4b4b4)Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(
Te6edf3reactionTb4b4b4(Te6edf3replyId Tff7b72= T79c0ff8T79c0ff4Tb4b4b4, Te6edf3userId Tff7b72= Ta5d6ff"Ta5d6ff!uTa5d6ff"Tb4b4b4, Te6edf3emoji Tff7b72= Ta5d6ff"Ta5d6ffπTa5d6ff"Tb4b4b4, Te6edf3timestamp Tff7b72= T79c0ff2Tb4b4b4, Te6edf3packetId Tff7b72= T79c0ff8T79c0ff4Tb4b4b4, Te6edf3ownerNodeNum Tff7b72= T79c0ff0Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3updateReactionByKeyTb4b4b4(
Te6edf3reactionTb4b4b4(Te6edf3replyId Tff7b72= T79c0ff8T79c0ff4Tb4b4b4, Te6edf3userId Tff7b72= Ta5d6ff"Ta5d6ff!uTa5d6ff"Tb4b4b4, Te6edf3emoji Tff7b72= Ta5d6ff"Ta5d6ffπTa5d6ff"Tb4b4b4, Te6edf3timestamp Tff7b72= T79c0ff9T79c0ff9T79c0ff9Tb4b4b4, Te6edf3packetId Tff7b72= T79c0ff8T79c0ff4Tb4b4b4, Te6edf3ownerNodeNum Tff7b72= T79c0ff0Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72val Te6edf3matching Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findReactionsWithIdTb4b4b4(T79c0ff8T79c0ff4Tb4b4b4)Tb4b4b4.Te6edf3filter Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3userId Tff7b72=Tff7b72= Ta5d6ff"Ta5d6ff!uTa5d6ff" Tff7b72&Tff7b72& Tffa657itTb4b4b4.Te6edf3emoji Tff7b72=Tff7b72= Ta5d6ff"Ta5d6ffπTa5d6ff" Tb4b4b4}
Te6edf3assertEqualsTb4b4b4(T79c0ff2Tb4b4b4, Te6edf3matchingTb4b4b4.Te6edf3sizeTb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3matchingTb4b4b4.Te6edf3all Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3timestamp Tff7b72=Tff7b72= T79c0ff9T79c0ff9T79c0ff9L Tb4b4b4}Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3setOfTb4b4b4(T79c0ff0Tb4b4b4, Te6edf3myNodeNumTb4b4b4)Tb4b4b4, Te6edf3matchingTb4b4b4.Te6edf3map Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3myNodeNum Tb4b4b4}Tb4b4b4.Te6edf3toSetTb4b4b4(Tb4b4b4)Tb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffupdateReactionByKeyPreservesExistingMyNodeNumTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3textPacketTb4b4b4(Ta5d6ff"Ta5d6ffcontactTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmsgTa5d6ff"Tb4b4b4, Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4, Te6edf3packetId Tff7b72= T79c0ff8T79c0ff1Tb4b4b4)Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3reactionTb4b4b4(Te6edf3replyId Tff7b72= T79c0ff8T79c0ff1Tb4b4b4, Te6edf3userId Tff7b72= Ta5d6ff"Ta5d6ff!uTa5d6ff"Tb4b4b4, Te6edf3emoji Tff7b72= Ta5d6ff"Ta5d6ffβ€οΈTa5d6ff"Tb4b4b4, Te6edf3timestamp Tff7b72= T79c0ff1Tb4b4b4, Te6edf3packetId Tff7b72= T79c0ff8T79c0ff1Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3replacement Tff7b72=
Te6edf3ReactionEntityTb4b4b4(
Te6edf3myNodeNum Tff7b72= T79c0ff0Tb4b4b4, T8b949e// placeholder β DAO must overwrite with existing
Te6edf3replyId Tff7b72= T79c0ff8T79c0ff1Tb4b4b4,
Te6edf3userId Tff7b72= Ta5d6ff"Ta5d6ff!uTa5d6ff"Tb4b4b4,
Te6edf3emoji Tff7b72= Ta5d6ff"Ta5d6ffβ€οΈTa5d6ff"Tb4b4b4,
Te6edf3timestamp Tff7b72= T79c0ff5T79c0ff5T79c0ff5Tb4b4b4,
Te6edf3packetId Tff7b72= T79c0ff8T79c0ff1Tb4b4b4,
Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3updateReactionByKeyTb4b4b4(Te6edf3replacementTb4b4b4)
Tff7b72val Te6edf3updated Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findReactionsWithIdTb4b4b4(T79c0ff8T79c0ff1Tb4b4b4)Tb4b4b4.Te6edf3find Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3userId Tff7b72=Tff7b72= Ta5d6ff"Ta5d6ff!uTa5d6ff" Tff7b72&Tff7b72& Tffa657itTb4b4b4.Te6edf3emoji Tff7b72=Tff7b72= Ta5d6ff"Ta5d6ffβ€οΈTa5d6ff" Tb4b4b4}
Te6edf3assertNotNullTb4b4b4(Te6edf3updatedTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3myNodeNumTb4b4b4, Te6edf3updatedTb4b4b4.Te6edf3myNodeNumTb4b4b4, Ta5d6ff"Ta5d6ffmyNodeNum must be borrowed from existing row, not 0Ta5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff5T79c0ff5T79c0ff5Tb4b4b4, Te6edf3updatedTb4b4b4.Te6edf3timestampTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffupdateReactionByKeyLeavesNonMatchingEmojiUntouchedTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3textPacketTb4b4b4(Ta5d6ff"Ta5d6ffcontactTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmsgTa5d6ff"Tb4b4b4, Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4, Te6edf3packetId Tff7b72= T79c0ff8T79c0ff2Tb4b4b4)Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3reactionTb4b4b4(Te6edf3replyId Tff7b72= T79c0ff8T79c0ff2Tb4b4b4, Te6edf3userId Tff7b72= Ta5d6ff"Ta5d6ff!uTa5d6ff"Tb4b4b4, Te6edf3emoji Tff7b72= Ta5d6ff"Ta5d6ffπTa5d6ff"Tb4b4b4, Te6edf3timestamp Tff7b72= T79c0ff1Tb4b4b4, Te6edf3packetId Tff7b72= T79c0ff8T79c0ff2Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3replacement Tff7b72=
Te6edf3ReactionEntityTb4b4b4(
Te6edf3myNodeNum Tff7b72= Te6edf3myNodeNumTb4b4b4,
Te6edf3replyId Tff7b72= T79c0ff8T79c0ff2Tb4b4b4,
Te6edf3userId Tff7b72= Ta5d6ff"Ta5d6ff!uTa5d6ff"Tb4b4b4,
Te6edf3emoji Tff7b72= Ta5d6ff"Ta5d6ffβ€οΈTa5d6ff"Tb4b4b4, T8b949e// different emoji β no match
Te6edf3timestamp Tff7b72= T79c0ff9T79c0ff9T79c0ff9Tb4b4b4,
Te6edf3packetId Tff7b72= T79c0ff8T79c0ff2Tb4b4b4,
Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3updateReactionByKeyTb4b4b4(Te6edf3replacementTb4b4b4)
Tff7b72val Te6edf3reactions Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findReactionsWithIdTb4b4b4(T79c0ff8T79c0ff2Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3reactionsTb4b4b4.Te6edf3sizeTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Ta5d6ff"Ta5d6ffπTa5d6ff"Tb4b4b4, Te6edf3reactionsTb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3emojiTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3reactionsTb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3timestampTb4b4b4, Ta5d6ff"Ta5d6fforiginal reaction untouchedTa5d6ff"Tb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffupdateReactionByKeyIsNoOpWhenNoMatchTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3reactionTb4b4b4(Te6edf3replyId Tff7b72= T79c0ff8T79c0ff3Tb4b4b4, Te6edf3userId Tff7b72= Ta5d6ff"Ta5d6ff!uTa5d6ff"Tb4b4b4, Te6edf3emoji Tff7b72= Ta5d6ff"Ta5d6ffπTa5d6ff"Tb4b4b4, Te6edf3timestamp Tff7b72= T79c0ff1Tb4b4b4, Te6edf3packetId Tff7b72= T79c0ff8T79c0ff3Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3replacement Tff7b72=
Te6edf3ReactionEntityTb4b4b4(
Te6edf3myNodeNum Tff7b72= Te6edf3myNodeNumTb4b4b4,
Te6edf3replyId Tff7b72= T79c0ff8T79c0ff3Tb4b4b4,
Te6edf3userId Tff7b72= Ta5d6ff"Ta5d6ff!otherTa5d6ff"Tb4b4b4, T8b949e// different user β no match
Te6edf3emoji Tff7b72= Ta5d6ff"Ta5d6ffπTa5d6ff"Tb4b4b4,
Te6edf3timestamp Tff7b72= T79c0ff9T79c0ff9T79c0ff9Tb4b4b4,
Te6edf3packetId Tff7b72= T79c0ff8T79c0ff3Tb4b4b4,
Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3updateReactionByKeyTb4b4b4(Te6edf3replacementTb4b4b4)
Tff7b72val Te6edf3reactions Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findReactionsWithIdTb4b4b4(T79c0ff8T79c0ff3Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3reactionsTb4b4b4.Te6edf3sizeTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3reactionsTb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3timestampTb4b4b4, Ta5d6ff"Ta5d6ffno reaction updatedTa5d6ff"Tb4b4b4)
Tb4b4b4}
T8b949e// ββ applySFPPStatus ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Tf0883e@Test
Tff7b72fun Td2a8ffapplySFPPStatusUpdatesMatchingPacketAndReactionInOneTransactionTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3packetId Tff7b72= T79c0ff1T79c0ff0T79c0ff0
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(
Te6edf3textPacketTb4b4b4(
Ta5d6ff"Ta5d6ffcontactTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffmsgTa5d6ff"Tb4b4b4,
Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff0T79c0ff0Tb4b4b4,
Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3from Tff7b72= Te6edf3NodeAddressTb4b4b4.Te6edf3ID_LOCALTb4b4b4,
Te6edf3to Tff7b72= Te6edf3NodeAddressTb4b4b4.Te6edf3ID_BROADCASTTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(
Te6edf3reactionTb4b4b4(
Te6edf3replyId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3userId Tff7b72= Te6edf3NodeAddressTb4b4b4.Te6edf3ID_LOCALTb4b4b4,
Te6edf3emoji Tff7b72= Ta5d6ff"Ta5d6ffπTa5d6ff"Tb4b4b4,
Te6edf3timestamp Tff7b72= T79c0ff1Tb4b4b4,
Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3to Tff7b72= Te6edf3NodeAddressTb4b4b4.Te6edf3ID_BROADCASTTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3applySFPPStatusTb4b4b4(
Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3from Tff7b72= Te6edf3myNodeNumTb4b4b4,
Te6edf3to Tff7b72= T79c0ff0Tb4b4b4,
Te6edf3hash Tff7b72= Te6edf3sfppHashTb4b4b4,
Te6edf3status Tff7b72= Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_ROUTINGTb4b4b4,
Te6edf3rxTime Tff7b72= T79c0ff5LTb4b4b4,
Te6edf3myNodeNum Tff7b72= Te6edf3myNodeNumTb4b4b4,
Tb4b4b4)
Tff7b72val Te6edf3packet Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findPacketsWithIdTb4b4b4(Te6edf3packetIdTb4b4b4)Tb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_ROUTINGTb4b4b4, Te6edf3packetTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3statusTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3sfppHashTb4b4b4, Te6edf3packetTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3sfppHashTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3sfppHashTb4b4b4, Te6edf3packetTb4b4b4.Te6edf3sfpp_hashTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff5Te6edf3_000LTb4b4b4, Te6edf3packetTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3timeTb4b4b4, Ta5d6ff"Ta5d6ffrxTime should be converted to millisTa5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff5Te6edf3_000LTb4b4b4, Te6edf3packetTb4b4b4.Te6edf3received_timeTb4b4b4)
Tff7b72val Te6edf3reaction Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findReactionsWithIdTb4b4b4(Te6edf3packetIdTb4b4b4)Tb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_ROUTINGTb4b4b4, Te6edf3reactionTb4b4b4.Te6edf3statusTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3sfppHashTb4b4b4, Te6edf3reactionTb4b4b4.Te6edf3sfpp_hashTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffapplySFPPStatusRollsBackPacketWhenReactionUpdateFailsTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3packetId Tff7b72= T79c0ff1T79c0ff0T79c0ff1
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(
Te6edf3textPacketTb4b4b4(
Ta5d6ff"Ta5d6ffrollback-statusTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffmsgTa5d6ff"Tb4b4b4,
Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff0T79c0ff0Tb4b4b4,
Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3from Tff7b72= Te6edf3NodeAddressTb4b4b4.Te6edf3ID_LOCALTb4b4b4,
Te6edf3to Tff7b72= Te6edf3NodeAddressTb4b4b4.Te6edf3ID_BROADCASTTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(
Te6edf3reactionTb4b4b4(
Te6edf3replyId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3userId Tff7b72= Te6edf3NodeAddressTb4b4b4.Te6edf3ID_LOCALTb4b4b4,
Te6edf3emoji Tff7b72= Ta5d6ff"Ta5d6ffπTa5d6ff"Tb4b4b4,
Te6edf3timestamp Tff7b72= T79c0ff1Tb4b4b4,
Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3to Tff7b72= Te6edf3NodeAddressTb4b4b4.Te6edf3ID_BROADCASTTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3databaseTb4b4b4.Te6edf3useWriterConnection Tb4b4b4{
Tffa657itTb4b4b4.Te6edf3executeSQLTb4b4b4(
Ta5d6ff"""
Ta5d6ff CREATE TRIGGER fail_reaction_status_update
BEFORE UPDATE ON reactions
WHEN OLD.packet_id = Tffd700$Te6edf3packetId
Ta5d6ff BEGIN
SELECT RAISE(ABORT, 'forced reaction update failure');
END
Ta5d6ff"""
Tb4b4b4.Te6edf3trimIndentTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Te6edf3assertFails Tb4b4b4{
Te6edf3packetDaoTb4b4b4.Te6edf3applySFPPStatusTb4b4b4(
Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3from Tff7b72= Te6edf3myNodeNumTb4b4b4,
Te6edf3to Tff7b72= T79c0ff0Tb4b4b4,
Te6edf3hash Tff7b72= Te6edf3sfppHashTb4b4b4,
Te6edf3status Tff7b72= Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_ROUTINGTb4b4b4,
Te6edf3rxTime Tff7b72= T79c0ff5LTb4b4b4,
Te6edf3myNodeNum Tff7b72= Te6edf3myNodeNumTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tff7b72val Te6edf3packet Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findPacketsWithIdTb4b4b4(Te6edf3packetIdTb4b4b4)Tb4b4b4.Te6edf3singleTb4b4b4(Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3MessageStatusTb4b4b4.Te6edf3UNKNOWNTb4b4b4, Te6edf3packetTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3statusTb4b4b4)
Te6edf3assertNullTb4b4b4(Te6edf3packetTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3sfppHashTb4b4b4)
Te6edf3assertNullTb4b4b4(Te6edf3packetTb4b4b4.Te6edf3sfpp_hashTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff1T79c0ff0T79c0ff0T79c0ff0LTb4b4b4, Te6edf3packetTb4b4b4.Te6edf3received_timeTb4b4b4)
Tff7b72val Te6edf3reaction Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findReactionsWithIdTb4b4b4(Te6edf3packetIdTb4b4b4)Tb4b4b4.Te6edf3singleTb4b4b4(Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3MessageStatusTb4b4b4.Te6edf3UNKNOWNTb4b4b4, Te6edf3reactionTb4b4b4.Te6edf3statusTb4b4b4)
Te6edf3assertNullTb4b4b4(Te6edf3reactionTb4b4b4.Te6edf3sfpp_hashTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff1LTb4b4b4, Te6edf3reactionTb4b4b4.Te6edf3timestampTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffapplySFPPStatusMatchesLocalNodeWithIdLocalTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3packetId Tff7b72= T79c0ff1T79c0ff1T79c0ff0
T8b949e// Packet stored with from = "^local" β local node sends with ID_LOCAL.
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(
Te6edf3textPacketTb4b4b4(
Ta5d6ff"Ta5d6ffcontactTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffmsgTa5d6ff"Tb4b4b4,
Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff0T79c0ff0Tb4b4b4,
Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3from Tff7b72= Te6edf3NodeAddressTb4b4b4.Te6edf3ID_LOCALTb4b4b4,
Te6edf3to Tff7b72= Te6edf3NodeAddressTb4b4b4.Te6edf3ID_BROADCASTTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
T8b949e// from = myNodeNum triggers isFromLocalNode = true, which matches data.from == ID_LOCAL.
Te6edf3packetDaoTb4b4b4.Te6edf3applySFPPStatusTb4b4b4(
Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3from Tff7b72= Te6edf3myNodeNumTb4b4b4,
Te6edf3to Tff7b72= T79c0ff0Tb4b4b4,
Te6edf3hash Tff7b72= Te6edf3sfppHashTb4b4b4,
Te6edf3status Tff7b72= Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_ROUTINGTb4b4b4,
Te6edf3rxTime Tff7b72= T79c0ff0LTb4b4b4,
Te6edf3myNodeNum Tff7b72= Te6edf3myNodeNumTb4b4b4,
Tb4b4b4)
Tff7b72val Te6edf3packet Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findPacketsWithIdTb4b4b4(Te6edf3packetIdTb4b4b4)Tb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_ROUTINGTb4b4b4, Te6edf3packetTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3statusTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffapplySFPPStatusBroadcastDestinationMatchesIdBroadcastTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3packetId Tff7b72= T79c0ff1T79c0ff2T79c0ff0
T8b949e// to = 0 (broadcast) should match data.to == "^all" (ID_BROADCAST).
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(
Te6edf3textPacketTb4b4b4(
Ta5d6ff"Ta5d6ffcontactTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffmsgTa5d6ff"Tb4b4b4,
Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff0T79c0ff0Tb4b4b4,
Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3from Tff7b72= Te6edf3NodeAddressTb4b4b4.Te6edf3ID_LOCALTb4b4b4,
Te6edf3to Tff7b72= Te6edf3NodeAddressTb4b4b4.Te6edf3ID_BROADCASTTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3applySFPPStatusTb4b4b4(
Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3from Tff7b72= Te6edf3myNodeNumTb4b4b4,
Te6edf3to Tff7b72= T79c0ff0Tb4b4b4,
Te6edf3hash Tff7b72= Te6edf3sfppHashTb4b4b4,
Te6edf3status Tff7b72= Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_ROUTINGTb4b4b4,
Te6edf3rxTime Tff7b72= T79c0ff0LTb4b4b4,
Te6edf3myNodeNum Tff7b72= Te6edf3myNodeNumTb4b4b4,
Tb4b4b4)
Tff7b72val Te6edf3packet Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findPacketsWithIdTb4b4b4(Te6edf3packetIdTb4b4b4)Tb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_ROUTINGTb4b4b4, Te6edf3packetTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3statusTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffapplySFPPStatusMatchesNumericUnicastAddressesTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3packetId Tff7b72= T79c0ff1T79c0ff2T79c0ff5
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(
Te6edf3textPacketTb4b4b4(Ta5d6ff"Ta5d6ffcontactTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmsgTa5d6ff"Tb4b4b4, Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff0T79c0ff0Tb4b4b4, Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4, Te6edf3from Tff7b72= Ta5d6ff"Ta5d6ff!0000007bTa5d6ff"Tb4b4b4, Te6edf3to Tff7b72= Ta5d6ff"Ta5d6ff!000001c8Ta5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3applySFPPStatusTb4b4b4(
Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3from Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4,
Te6edf3to Tff7b72= T79c0ff4T79c0ff5T79c0ff6Tb4b4b4,
Te6edf3hash Tff7b72= Te6edf3sfppHashTb4b4b4,
Te6edf3status Tff7b72= Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_ROUTINGTb4b4b4,
Te6edf3rxTime Tff7b72= T79c0ff0LTb4b4b4,
Te6edf3myNodeNum Tff7b72= Te6edf3myNodeNumTb4b4b4,
Tb4b4b4)
Tff7b72val Te6edf3packet Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findPacketsWithIdTb4b4b4(Te6edf3packetIdTb4b4b4)Tb4b4b4.Te6edf3singleTb4b4b4(Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_ROUTINGTb4b4b4, Te6edf3packetTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3statusTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3sfppHashTb4b4b4, Te6edf3packetTb4b4b4.Te6edf3sfpp_hashTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffapplySFPPStatusDoesNotDowngradeConfirmedToRoutingTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3packetId Tff7b72= T79c0ff1T79c0ff3T79c0ff0
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(
Te6edf3textPacketTb4b4b4(
Ta5d6ff"Ta5d6ffcontactTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffmsgTa5d6ff"Tb4b4b4,
Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff0T79c0ff0Tb4b4b4,
Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3from Tff7b72= Te6edf3NodeAddressTb4b4b4.Te6edf3ID_LOCALTb4b4b4,
Te6edf3to Tff7b72= Te6edf3NodeAddressTb4b4b4.Te6edf3ID_BROADCASTTb4b4b4,
Te6edf3status Tff7b72= Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_CONFIRMEDTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(
Te6edf3reactionTb4b4b4(
Te6edf3replyId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3userId Tff7b72= Te6edf3NodeAddressTb4b4b4.Te6edf3ID_LOCALTb4b4b4,
Te6edf3emoji Tff7b72= Ta5d6ff"Ta5d6ffπTa5d6ff"Tb4b4b4,
Te6edf3timestamp Tff7b72= T79c0ff1Tb4b4b4,
Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3to Tff7b72= Te6edf3NodeAddressTb4b4b4.Te6edf3ID_BROADCASTTb4b4b4,
Te6edf3status Tff7b72= Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_CONFIRMEDTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3applySFPPStatusTb4b4b4(
Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3from Tff7b72= Te6edf3myNodeNumTb4b4b4,
Te6edf3to Tff7b72= T79c0ff0Tb4b4b4,
Te6edf3hash Tff7b72= Te6edf3sfppHashTb4b4b4,
Te6edf3status Tff7b72= Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_ROUTINGTb4b4b4,
Te6edf3rxTime Tff7b72= T79c0ff5LTb4b4b4,
Te6edf3myNodeNum Tff7b72= Te6edf3myNodeNumTb4b4b4,
Tb4b4b4)
Tff7b72val Te6edf3packet Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findPacketsWithIdTb4b4b4(Te6edf3packetIdTb4b4b4)Tb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_CONFIRMEDTb4b4b4, Te6edf3packetTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3statusTb4b4b4, Ta5d6ff"Ta5d6ffpacket must not be downgradedTa5d6ff"Tb4b4b4)
Tff7b72val Te6edf3reaction Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findReactionsWithIdTb4b4b4(Te6edf3packetIdTb4b4b4)Tb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_CONFIRMEDTb4b4b4, Te6edf3reactionTb4b4b4.Te6edf3statusTb4b4b4, Ta5d6ff"Ta5d6ffreaction must not be downgradedTa5d6ff"Tb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffapplySFPPStatusLeavesNonMatchingAddressesUntouchedTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3packetId Tff7b72= T79c0ff1T79c0ff4T79c0ff0
T8b949e// Packet from node 123 (!0000007b), not from local node.
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(
Te6edf3textPacketTb4b4b4(
Ta5d6ff"Ta5d6ffcontactTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffmsgTa5d6ff"Tb4b4b4,
Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff0T79c0ff0Tb4b4b4,
Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3from Tff7b72= Ta5d6ff"Ta5d6ff!0000007bTa5d6ff"Tb4b4b4,
Te6edf3to Tff7b72= Te6edf3NodeAddressTb4b4b4.Te6edf3ID_BROADCASTTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
T8b949e// Call with from = 456 (!000001c8) β should NOT match.
Te6edf3packetDaoTb4b4b4.Te6edf3applySFPPStatusTb4b4b4(
Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3from Tff7b72= T79c0ff4T79c0ff5T79c0ff6Tb4b4b4,
Te6edf3to Tff7b72= T79c0ff0Tb4b4b4,
Te6edf3hash Tff7b72= Te6edf3sfppHashTb4b4b4,
Te6edf3status Tff7b72= Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_ROUTINGTb4b4b4,
Te6edf3rxTime Tff7b72= T79c0ff0LTb4b4b4,
Te6edf3myNodeNum Tff7b72= Te6edf3myNodeNumTb4b4b4,
Tb4b4b4)
Tff7b72val Te6edf3packet Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findPacketsWithIdTb4b4b4(Te6edf3packetIdTb4b4b4)Tb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3MessageStatusTb4b4b4.Te6edf3UNKNOWNTb4b4b4, Te6edf3packetTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3statusTb4b4b4, Ta5d6ff"Ta5d6ffnon-matching packet should be untouchedTa5d6ff"Tb4b4b4)
Te6edf3assertNullTb4b4b4(Te6edf3packetTb4b4b4.Te6edf3sfpp_hashTb4b4b4)
Tb4b4b4}
T8b949e// ββ applySFPPStatusByHash ββββββββββββββββββββββββββββββββββββββββββββββββββββ
Tf0883e@Test
Tff7b72fun Td2a8ffapplySFPPStatusByHashMatchesByHashPrefixTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3packetId Tff7b72= T79c0ff2T79c0ff0T79c0ff0
Tff7b72val Te6edf3fullHash Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4, T79c0ff2Tb4b4b4, T79c0ff3Tb4b4b4, T79c0ff4Tb4b4b4, T79c0ff5Tb4b4b4, T79c0ff6Tb4b4b4, T79c0ff7Tb4b4b4, T79c0ff8Tb4b4b4, T79c0ff9Tb4b4b4, T79c0ff1T79c0ff0Tb4b4b4, T79c0ff1T79c0ff1Tb4b4b4, T79c0ff1T79c0ff2Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3hashPrefix Tff7b72= Te6edf3fullHashTb4b4b4.Te6edf3substringTb4b4b4(T79c0ff0Tb4b4b4, T79c0ff8Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3textPacketTb4b4b4(Ta5d6ff"Ta5d6ffcontactTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmsgTa5d6ff"Tb4b4b4, Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff0T79c0ff0Tb4b4b4, Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4, Te6edf3sfppHash Tff7b72= Te6edf3fullHashTb4b4b4)Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(
Te6edf3reactionTb4b4b4(
Te6edf3replyId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3userId Tff7b72= Ta5d6ff"Ta5d6ff!uTa5d6ff"Tb4b4b4,
Te6edf3emoji Tff7b72= Ta5d6ff"Ta5d6ffπTa5d6ff"Tb4b4b4,
Te6edf3timestamp Tff7b72= T79c0ff1Tb4b4b4,
Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3sfppHash Tff7b72= Te6edf3fullHashTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3applySFPPStatusByHashTb4b4b4(Te6edf3hashPrefixTb4b4b4, Te6edf3status Tff7b72= Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_ROUTINGTb4b4b4, Te6edf3rxTime Tff7b72= T79c0ff5LTb4b4b4)
Tff7b72val Te6edf3packet Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findPacketBySfppHashTb4b4b4(Te6edf3fullHashTb4b4b4)
Te6edf3assertNotNullTb4b4b4(Te6edf3packetTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_ROUTINGTb4b4b4, Te6edf3packetTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3statusTb4b4b4)
Tff7b72val Te6edf3reaction Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findReactionBySfppHashTb4b4b4(Te6edf3fullHashTb4b4b4)
Te6edf3assertNotNullTb4b4b4(Te6edf3reactionTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_ROUTINGTb4b4b4, Te6edf3reactionTb4b4b4.Te6edf3statusTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffapplySFPPStatusByHashRollsBackPacketWhenReactionUpdateFailsTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3packetId Tff7b72= T79c0ff2T79c0ff0T79c0ff5
Tff7b72val Te6edf3fullHash Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff9Tb4b4b4, T79c0ff8Tb4b4b4, T79c0ff7Tb4b4b4, T79c0ff6Tb4b4b4, T79c0ff5Tb4b4b4, T79c0ff4Tb4b4b4, T79c0ff3Tb4b4b4, T79c0ff2Tb4b4b4, T79c0ff1Tb4b4b4, T79c0ff0Tb4b4b4, T79c0ff1Tb4b4b4, T79c0ff2Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3hashPrefix Tff7b72= Te6edf3fullHashTb4b4b4.Te6edf3substringTb4b4b4(T79c0ff0Tb4b4b4, T79c0ff8Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3textPacketTb4b4b4(Ta5d6ff"Ta5d6ffcontactTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmsgTa5d6ff"Tb4b4b4, Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff0T79c0ff0Tb4b4b4, Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4, Te6edf3sfppHash Tff7b72= Te6edf3fullHashTb4b4b4)Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(
Te6edf3reactionTb4b4b4(
Te6edf3replyId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3userId Tff7b72= Ta5d6ff"Ta5d6ff!uTa5d6ff"Tb4b4b4,
Te6edf3emoji Tff7b72= Ta5d6ff"Ta5d6ffπTa5d6ff"Tb4b4b4,
Te6edf3timestamp Tff7b72= T79c0ff1Tb4b4b4,
Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3sfppHash Tff7b72= Te6edf3fullHashTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3databaseTb4b4b4.Te6edf3useWriterConnection Tb4b4b4{
Tffa657itTb4b4b4.Te6edf3executeSQLTb4b4b4(
Ta5d6ff"""
Ta5d6ff CREATE TRIGGER fail_reaction_hash_status_update
BEFORE UPDATE ON reactions
WHEN OLD.packet_id = Tffd700$Te6edf3packetId
Ta5d6ff BEGIN
SELECT RAISE(ABORT, 'forced reaction hash update failure');
END
Ta5d6ff"""
Tb4b4b4.Te6edf3trimIndentTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Te6edf3assertFails Tb4b4b4{ Te6edf3packetDaoTb4b4b4.Te6edf3applySFPPStatusByHashTb4b4b4(Te6edf3hashPrefixTb4b4b4, Te6edf3status Tff7b72= Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_ROUTINGTb4b4b4, Te6edf3rxTime Tff7b72= T79c0ff5LTb4b4b4) Tb4b4b4}
Tff7b72val Te6edf3packet Tff7b72= Te6edf3assertNotNullTb4b4b4(Te6edf3packetDaoTb4b4b4.Te6edf3findPacketBySfppHashTb4b4b4(Te6edf3fullHashTb4b4b4)Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3MessageStatusTb4b4b4.Te6edf3UNKNOWNTb4b4b4, Te6edf3packetTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3statusTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff1T79c0ff0T79c0ff0T79c0ff0LTb4b4b4, Te6edf3packetTb4b4b4.Te6edf3received_timeTb4b4b4)
Tff7b72val Te6edf3reaction Tff7b72= Te6edf3assertNotNullTb4b4b4(Te6edf3packetDaoTb4b4b4.Te6edf3findReactionBySfppHashTb4b4b4(Te6edf3fullHashTb4b4b4)Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3MessageStatusTb4b4b4.Te6edf3UNKNOWNTb4b4b4, Te6edf3reactionTb4b4b4.Te6edf3statusTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff1LTb4b4b4, Te6edf3reactionTb4b4b4.Te6edf3timestampTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffapplySFPPStatusByHashDoesNotDowngradeConfirmedToRoutingTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3packetId Tff7b72= T79c0ff2T79c0ff1T79c0ff0
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(
Te6edf3textPacketTb4b4b4(
Ta5d6ff"Ta5d6ffcontactTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffmsgTa5d6ff"Tb4b4b4,
Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff0T79c0ff0Tb4b4b4,
Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4,
Te6edf3status Tff7b72= Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_CONFIRMEDTb4b4b4,
Te6edf3sfppHash Tff7b72= Te6edf3sfppHashTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3applySFPPStatusByHashTb4b4b4(Te6edf3sfppHashTb4b4b4, Te6edf3status Tff7b72= Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_ROUTINGTb4b4b4, Te6edf3rxTime Tff7b72= T79c0ff5LTb4b4b4)
Tff7b72val Te6edf3packet Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findPacketBySfppHashTb4b4b4(Te6edf3sfppHashTb4b4b4)
Te6edf3assertNotNullTb4b4b4(Te6edf3packetTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_CONFIRMEDTb4b4b4, Te6edf3packetTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3statusTb4b4b4, Ta5d6ff"Ta5d6ffconfirmed packet must not be downgradedTa5d6ff"Tb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffapplySFPPStatusByHashLeavesUnrelatedHashUntouchedTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3packetId Tff7b72= T79c0ff2T79c0ff2T79c0ff0
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3textPacketTb4b4b4(Ta5d6ff"Ta5d6ffcontactTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmsgTa5d6ff"Tb4b4b4, Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff0T79c0ff0Tb4b4b4, Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4, Te6edf3sfppHash Tff7b72= Te6edf3sfppHashTb4b4b4)Tb4b4b4)
T8b949e// Apply with a completely different hash prefix β should not touch the packet.
Te6edf3packetDaoTb4b4b4.Te6edf3applySFPPStatusByHashTb4b4b4(Te6edf3otherHashTb4b4b4, Te6edf3status Tff7b72= Te6edf3MessageStatusTb4b4b4.Te6edf3SFPP_ROUTINGTb4b4b4, Te6edf3rxTime Tff7b72= T79c0ff5LTb4b4b4)
Tff7b72val Te6edf3packet Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findPacketBySfppHashTb4b4b4(Te6edf3sfppHashTb4b4b4)
Te6edf3assertNotNullTb4b4b4(Te6edf3packetTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3MessageStatusTb4b4b4.Te6edf3UNKNOWNTb4b4b4, Te6edf3packetTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3statusTb4b4b4, Ta5d6ff"Ta5d6ffunrelated hash should be untouchedTa5d6ff"Tb4b4b4)
Tb4b4b4}
T8b949e// ββ deleteMessagesAtomic βββββββββββββββββββββββββββββββββββββββββββββββββββββ
Tf0883e@Test
Tff7b72fun Td2a8ffdeleteMessagesAtomicDeletesPacketsAndReactionsTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3packetId Tff7b72= T79c0ff3T79c0ff0T79c0ff0
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3textPacketTb4b4b4(Ta5d6ff"Ta5d6ffcontactTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmsgTa5d6ff"Tb4b4b4, Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4, Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4)Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3reactionTb4b4b4(Te6edf3replyId Tff7b72= Te6edf3packetIdTb4b4b4, Te6edf3userId Tff7b72= Ta5d6ff"Ta5d6ff!uTa5d6ff"Tb4b4b4, Te6edf3emoji Tff7b72= Ta5d6ff"Ta5d6ffπTa5d6ff"Tb4b4b4, Te6edf3timestamp Tff7b72= T79c0ff1Tb4b4b4, Te6edf3packetId Tff7b72= Te6edf3packetIdTb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3uuids Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3getMessagesFromTb4b4b4(Ta5d6ff"Ta5d6ffcontactTa5d6ff"Tb4b4b4)Tb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3map Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3packetTb4b4b4.Te6edf3uuid Tb4b4b4}
Te6edf3assertTrueTb4b4b4(Te6edf3uuidsTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3deleteMessagesAtomicTb4b4b4(Te6edf3uuidsTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff0Tb4b4b4, Te6edf3packetDaoTb4b4b4.Te6edf3getMessageCountTb4b4b4(Ta5d6ff"Ta5d6ffcontactTa5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3packetDaoTb4b4b4.Te6edf3findReactionsWithIdTb4b4b4(Te6edf3packetIdTb4b4b4)Tb4b4b4.Te6edf3isEmptyTb4b4b4(Tb4b4b4)Tb4b4b4, Ta5d6ff"Ta5d6ffreactions should be deleted with their packetsTa5d6ff"Tb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffdeleteMessagesAtomicEmptyListIsNoOpTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3contact Tff7b72= Ta5d6ff"Ta5d6ffempty-testTa5d6ff"
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3textPacketTb4b4b4(Te6edf3contactTb4b4b4, Ta5d6ff"Ta5d6ffmsgTa5d6ff"Tb4b4b4, Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4, Te6edf3packetId Tff7b72= T79c0ff3T79c0ff1T79c0ff0Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3before Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3getMessageCountTb4b4b4(Te6edf3contactTb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3deleteMessagesAtomicTb4b4b4(Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3beforeTb4b4b4, Te6edf3packetDaoTb4b4b4.Te6edf3getMessageCountTb4b4b4(Te6edf3contactTb4b4b4)Tb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffdeleteMessagesAtomicCrossesChunkBoundaryAndDeletesAllTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3contact Tff7b72= Ta5d6ff"Ta5d6ffchunk-boundaryTa5d6ff"
Tff7b72val Te6edf3firstPacketId Tff7b72= T79c0ff3T79c0ff1T79c0ff1
Tff7b72val Te6edf3secondPacketId Tff7b72= T79c0ff3T79c0ff1T79c0ff2
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3textPacketTb4b4b4(Te6edf3contactTb4b4b4, Ta5d6ff"Ta5d6fffirstTa5d6ff"Tb4b4b4, Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4, Te6edf3packetId Tff7b72= Te6edf3firstPacketIdTb4b4b4)Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3textPacketTb4b4b4(Te6edf3contactTb4b4b4, Ta5d6ff"Ta5d6ffsecondTa5d6ff"Tb4b4b4, Te6edf3time Tff7b72= T79c0ff2T79c0ff0T79c0ff0Tb4b4b4, Te6edf3packetId Tff7b72= Te6edf3secondPacketIdTb4b4b4)Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(
Te6edf3reactionTb4b4b4(
Te6edf3replyId Tff7b72= Te6edf3firstPacketIdTb4b4b4,
Te6edf3userId Tff7b72= Ta5d6ff"Ta5d6ff!rollbackTa5d6ff"Tb4b4b4,
Te6edf3emoji Tff7b72= Ta5d6ff"Ta5d6ffπTa5d6ff"Tb4b4b4,
Te6edf3timestamp Tff7b72= T79c0ff1Tb4b4b4,
Te6edf3packetId Tff7b72= Te6edf3firstPacketIdTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
T8b949e// Also insert a packet that should survive the delete.
Tff7b72val Te6edf3survivorContact Tff7b72= Ta5d6ff"Ta5d6ffsurvivorTa5d6ff"
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3textPacketTb4b4b4(Te6edf3survivorContactTb4b4b4, Ta5d6ff"Ta5d6ffkeepTa5d6ff"Tb4b4b4, Te6edf3time Tff7b72= T79c0ff9T79c0ff9T79c0ff9Te6edf3_999Tb4b4b4, Te6edf3packetId Tff7b72= T79c0ff9Te6edf3_999Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3firstUuid Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findPacketsWithIdTb4b4b4(Te6edf3firstPacketIdTb4b4b4)Tb4b4b4.Te6edf3singleTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3uuid
Tff7b72val Te6edf3secondUuid Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findPacketsWithIdTb4b4b4(Te6edf3secondPacketIdTb4b4b4)Tb4b4b4.Te6edf3singleTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3uuid
Te6edf3packetDaoTb4b4b4.Te6edf3deleteMessagesAtomicTb4b4b4(Te6edf3crossChunkUuidsTb4b4b4(Te6edf3firstUuidTb4b4b4, Te6edf3secondUuidTb4b4b4)Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff0Tb4b4b4, Te6edf3packetDaoTb4b4b4.Te6edf3getMessageCountTb4b4b4(Te6edf3contactTb4b4b4)Tb4b4b4, Ta5d6ff"Ta5d6ffall chunked packets deletedTa5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3packetDaoTb4b4b4.Te6edf3getMessageCountTb4b4b4(Te6edf3survivorContactTb4b4b4)Tb4b4b4, Ta5d6ff"Ta5d6ffnon-selected packet untouchedTa5d6ff"Tb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffdeleteMessagesAtomicRollsBackEarlierChunkWhenLaterChunkFailsTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3seedMyNodeInfoTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3contact Tff7b72= Ta5d6ff"Ta5d6ffchunk-rollbackTa5d6ff"
Tff7b72val Te6edf3firstPacketId Tff7b72= T79c0ff3T79c0ff2T79c0ff0
Tff7b72val Te6edf3secondPacketId Tff7b72= T79c0ff3T79c0ff2T79c0ff1
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3textPacketTb4b4b4(Te6edf3contactTb4b4b4, Ta5d6ff"Ta5d6fffirstTa5d6ff"Tb4b4b4, Te6edf3time Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4, Te6edf3packetId Tff7b72= Te6edf3firstPacketIdTb4b4b4)Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(Te6edf3textPacketTb4b4b4(Te6edf3contactTb4b4b4, Ta5d6ff"Ta5d6ffsecondTa5d6ff"Tb4b4b4, Te6edf3time Tff7b72= T79c0ff2T79c0ff0T79c0ff0Tb4b4b4, Te6edf3packetId Tff7b72= Te6edf3secondPacketIdTb4b4b4)Tb4b4b4)
Te6edf3packetDaoTb4b4b4.Te6edf3insertTb4b4b4(
Te6edf3reactionTb4b4b4(
Te6edf3replyId Tff7b72= Te6edf3firstPacketIdTb4b4b4,
Te6edf3userId Tff7b72= Ta5d6ff"Ta5d6ff!rollbackTa5d6ff"Tb4b4b4,
Te6edf3emoji Tff7b72= Ta5d6ff"Ta5d6ffπTa5d6ff"Tb4b4b4,
Te6edf3timestamp Tff7b72= T79c0ff1Tb4b4b4,
Te6edf3packetId Tff7b72= Te6edf3firstPacketIdTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72val Te6edf3firstUuid Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findPacketsWithIdTb4b4b4(Te6edf3firstPacketIdTb4b4b4)Tb4b4b4.Te6edf3singleTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3uuid
Tff7b72val Te6edf3secondUuid Tff7b72= Te6edf3packetDaoTb4b4b4.Te6edf3findPacketsWithIdTb4b4b4(Te6edf3secondPacketIdTb4b4b4)Tb4b4b4.Te6edf3singleTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3uuid
Te6edf3databaseTb4b4b4.Te6edf3useWriterConnection Tb4b4b4{
Tffa657itTb4b4b4.Te6edf3executeSQLTb4b4b4(
Ta5d6ff"""
Ta5d6ff CREATE TRIGGER fail_second_delete_chunk
BEFORE DELETE ON packet
WHEN OLD.packet_id = Tffd700$Te6edf3secondPacketId
Ta5d6ff BEGIN
SELECT RAISE(ABORT, 'forced later-chunk delete failure');
END
Ta5d6ff"""
Tb4b4b4.Te6edf3trimIndentTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Te6edf3assertFails Tb4b4b4{ Te6edf3packetDaoTb4b4b4.Te6edf3deleteMessagesAtomicTb4b4b4(Te6edf3crossChunkUuidsTb4b4b4(Te6edf3firstUuidTb4b4b4, Te6edf3secondUuidTb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3assertEqualsTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3packetDaoTb4b4b4.Te6edf3findPacketsWithIdTb4b4b4(Te6edf3firstPacketIdTb4b4b4)Tb4b4b4.Te6edf3sizeTb4b4b4, Ta5d6ff"Ta5d6ffthe first chunk must roll backTa5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3packetDaoTb4b4b4.Te6edf3findPacketsWithIdTb4b4b4(Te6edf3secondPacketIdTb4b4b4)Tb4b4b4.Te6edf3sizeTb4b4b4, Ta5d6ff"Ta5d6ffthe failing row must remainTa5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3packetDaoTb4b4b4.Te6edf3findReactionsWithIdTb4b4b4(Te6edf3firstPacketIdTb4b4b4)Tb4b4b4.Te6edf3sizeTb4b4b4, Ta5d6ff"Ta5d6fffirst-chunk reactions must roll backTa5d6ff"Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Served by rngit 1.5.0 - Generated in 0.24s